﻿module CalcViewModel

open System
open ImpromptuInterface.MVVM
open ImpromptuInterface.FSharp

type ICalcViewModel =
    abstract member LeftSideEq   : decimal with get,set
    abstract member RightSideEq  : decimal with get,set
    abstract member Display      : string  with get,set
    abstract member LeftBuffer   : string  with get,set
    abstract member RightBuffer  : string  with get,set
    abstract member SymbolBuffer : string  with get,set
    abstract member LastBuffer   : string  with get,set

type CalcViewModel() as this=
    class
        inherit ImpromptuViewModel<ICalcViewModel>()
        
        let (|Set|NotSet|) s = if String.IsNullOrWhiteSpace(s) then NotSet else Set 

        do
            this.Contract.LeftBuffer <- String.Empty
            this.Contract.RightBuffer <- String.Empty  
            this.Contract.SymbolBuffer <- String.Empty
            dynAddAssign(this.OnChanged)?LeftBuffer <- ImpromptuViewModel.ChangedHandler(
                fun sender e -> 
                    this.Contract.Display <- this.Contract.LeftBuffer 
                    this?LeftSideEq <- this.Contract.LeftBuffer
            )
            dynAddAssign(this.OnChanged)?RightBuffer <- ImpromptuViewModel.ChangedHandler(
                fun sender e -> 
                    this.Contract.Display <- this.Contract.RightBuffer 
                    this?RightSideEq <- this.Contract.RightBuffer
            )
            dynAddAssign(this.OnChanged)?SymbolBuffer <- ImpromptuViewModel.ChangedHandler(
                fun sender e -> 
                    this.Contract.Display <- this.Contract.SymbolBuffer 
            )


        member this.Calculate (unit) : decimal=
            let calc x y =
                     match this.Contract.SymbolBuffer with
                        | "+" -> x + y
                        | "-" -> x - y
                        | "*" -> x * y  
                        | "/" -> x / y
                        | ___ -> raise (Exception "Unknown Symbol")
            calc this.Contract.LeftSideEq this.Contract.RightSideEq


        member this.ClearAll() = this.ClearAll(null)
        member this.ClearAll(dummy:obj) : unit =
            this.Contract.LeftBuffer <- String.Empty
            this.Contract.RightBuffer <- String.Empty
            this.Contract.SymbolBuffer <- String.Empty
            this.Contract.Display <- String.Empty
            this.Contract.LastBuffer <-String.Empty
           

        member this.RunEquation() = this.RunEquation(null)
        member this.RunEquation(dummy:obj) : unit =
            try
                let result = match this.Contract.RightBuffer with
                                                | Set -> this.Calculate()
                                                | NotSet-> this.Contract.LeftSideEq
                this.ClearAll()
                this?LastBuffer <- result;
                let actOnResult r = if dummy <> null then
                                        this.Contract.Display <- r
                                    else
                                        this.Contract.LeftBuffer <- r
                actOnResult(this.Contract.LastBuffer)
            with
                | _ -> this.ClearAll()
                       this.Contract.Display <- "Error"


        member this.Number(content:string) : unit =
            match this.Contract.SymbolBuffer with
                | NotSet -> this.Contract.LeftBuffer <- this.Contract.LeftBuffer + content
                | Set    -> this.Contract.RightBuffer <- this.Contract.RightBuffer + content


        member this.Symbol(content:string) : unit =
            match this.Contract.LeftBuffer with
                | NotSet -> this.Contract.LeftBuffer <- this.Contract.LastBuffer
                | ______ -> ignore()
            match this.Contract.RightBuffer with
                | Set -> this.RunEquation()
                | ___ -> ignore()
            this.Contract.SymbolBuffer <- String.Empty
            this.Contract.SymbolBuffer <- content

           
        member this.ClearRecent() = this.ClearRecent(null) 
        member this.ClearRecent(dummy:obj) : unit =
            match (this.Contract.LeftBuffer, this.Contract.SymbolBuffer, this.Contract.RightBuffer) with
                | (_, _, Set) -> this.Contract.RightBuffer <- String.Empty
                                 this.Contract.Display <- this.Contract.SymbolBuffer
                | (_, Set, _) -> this.Contract.SymbolBuffer <- String.Empty
                                 this.Contract.Display <- this.Contract.LeftBuffer
                |  _________  -> this.ClearAll()
    end